package com.gitee.wsl.collections.map.multi

import com.gitee.wsl.collections.delegate.DelegatingMutableMap
import com.gitee.wsl.collections.map.multi.MultiValueMap.Companion.DEFAULT_INITIAL_CAPACITY
import com.gitee.wsl.collections.map.multi.MultiValueMap.Companion.DEFAULT_LOAD_FACTOR
import com.gitee.wsl.ext.collection.getByIndex
import com.gitee.wsl.func.factory.Factory

fun<K, V> listValueMap(initialCapacity: Int = DEFAULT_INITIAL_CAPACITY,
                       loadFactor: Float = DEFAULT_LOAD_FACTOR
) = MultiValueMap<K, V,MutableList<V>>(
    initialCapacity = initialCapacity,
    loadFactor = loadFactor
    ){
    mutableListOf<V>()
    }

fun<K, V> setValueMap(initialCapacity: Int = DEFAULT_INITIAL_CAPACITY,
                       loadFactor: Float = DEFAULT_LOAD_FACTOR
) = MultiValueMap<K, V,MutableSet<V>>(
    initialCapacity = initialCapacity,
    loadFactor = loadFactor
){
    mutableSetOf<V>()
}

/**
 * 值作为集合的Map实现，通过调用putValue可以在相同key时加入多个值，多个值用集合表示
 *
 * @param <K> 键类型
 * @param <V> 值类型
 * @param <C> 集合类型
 * @author looly
 * @since 5.7.4
</C></V></K> */
class MultiValueMap<K, V, C : MutableCollection<V>>(
    initialCapacity: Int = DEFAULT_INITIAL_CAPACITY,
    loadFactor: Float = DEFAULT_LOAD_FACTOR,
    val createCollection: Factory<C>
) : DelegatingMutableMap<K, C>(HashMap(initialCapacity, loadFactor)) {

    /**
     * 构造
     *
     * @param m Map
     */
    constructor(m: Map<out K, C>,
                createCollection: Factory<C>
    ) : this(DEFAULT_LOAD_FACTOR, m,createCollection)

    /**
     * 构造
     *
     * @param loadFactor 加载因子
     * @param m          Map
     */
    constructor(loadFactor: Float,
                m: Map<out K, C>,
                createCollection: Factory<C>
    ) : this(m.size, loadFactor,createCollection) {
        this.putAll(m)
    }

    // ------------------------------------------------------------------------- Constructor end
    /**
     * 放入所有value
     *
     * @param m valueMap
     * @since 5.7.4
     */
    fun putAllValues(m: Map<K, Collection<V>>) {
        m.forEach{  entry->
                val (key, valueColl) = entry
                //if (null != valueColl) {
                  valueColl.forEach{ value -> putValue(key, value) }
                //}
         }
    }

    /**
     * 放入Value<br></br>
     * 如果键对应值列表有值，加入，否则创建一个新列表后加入
     *
     * @param key   键
     * @param value 值
     */
    fun putValue(key: K, value: V) {
        var collection = this[key]
        if (null == collection) {
            collection = createCollection()
            this.put(key, collection)
        }
        collection.add(value)
    }

    /**
     * 获取值
     *
     * @param key   键
     * @param index 第几个值的索引，越界返回null
     * @return 值或null
     */
    fun get(key: K, index: Int): V? {
        val collection:C? = get(key)
        return collection?.getByIndex(index)
    }

    /**
     * 移除value集合中的某个值
     *
     * @param key   键
     * @param value 集合中的某个值
     * @return 是否删除成功
     */
    fun removeValue(key: K, value: V): Boolean {
        val collection = this[key]
        return null != collection && collection.remove(value)
    }

    /**
     * 移除value集合中的某些值
     *
     * @param key   键
     * @param values 集合中的某些值
     * @return 是否删除成功
     */
    fun removeValues(key: K, values: Collection<V>): Boolean {
        val collection = this[key]
        return null != collection && collection.removeAll(values)
    }

    /**
     * 创建集合<br></br>
     * 此方法用于创建在putValue后追加值所在的集合，子类实现此方法创建不同类型的集合
     *
     * @return [Collection]
     */
    //protected abstract fun createCollection(): C

    companion object {

        /**
         * 默认集合初始大小
         */
        protected const val DEFAULT_COLLECTION_INITIAL_CAPACITY: Int = 3

        /**
         * 默认增长因子
         */
        const val DEFAULT_LOAD_FACTOR: Float = 0.75f
        /**
         * 默认初始大小
         */
        const val DEFAULT_INITIAL_CAPACITY: Int = 1 shl 4 // aka 16
    }
}
